package com.wiki.aop;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.List;

@Aspect
@Component
@Slf4j
public class LoggingAspect {

    private static final int MAX_LOG_LENGTH = 1000; // 定义最大日志长度
    private static final String[] SENSITIVE_FIELD_NAMES = {"password", "creditCard"};

    @Before("execution(* com.wiki.controller..*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        // 日志流水号
        MDC.put("logId", String.valueOf(System.currentTimeMillis()));
        // 请求参数
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 判断是否为空
        if (servletRequestAttributes == null) {
            return;
        }
        // 获取请求对象
        HttpServletRequest request = servletRequestAttributes.getRequest();
        // 获取请求地址
        String ip = request.getRemoteAddr();
        // 获取请求方法
        String method = request.getMethod();
        // 获取请求路径
        String uri = request.getRequestURI();
        // 获取请求类名
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        // 输出请求信息
        log.info("请求地址：{}", ip);
        log.info("请求方式：{}", method);
        log.info("请求路径：{}", uri);
        log.info("请求类名：{}", declaringTypeName);

        String remoteIPAddress = getRemoteIPAddress(request);
        // 输出日志
        log.info("客户端IP地址：{}", remoteIPAddress);


        // 获取请求参数
        Object[] args = joinPoint.getArgs();
        log.info("请求参数：(所有类型) {}", JSONObject.toJSONString(args));

        // 获取请求参数，过滤ServletRequest、ServletResponse、MultipartFile类型的参数
        List<Object> objectList = Arrays.asList(args).stream()
                .filter(arg -> {
                    // 忽略ServletRequest、ServletResponse、MultipartFile类型的参数
                    if (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile) {
                        return false;
                    }
                    return true;
                }).toList();
        log.info("请求参数：(指定类型) {}", JSONObject.toJSONString(objectList));

        // 排除敏感字段
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludeFilter = filters.addFilter();
        excludeFilter.addExcludes(SENSITIVE_FIELD_NAMES);
        log.info("请求参数：(排除敏感字段) {}", JSONObject.toJSONString(args, excludeFilter));
    }

    // 环绕通知
    @Around("execution(* com.wiki.controller..*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("-------------------LogAspect  doAround --------------------------");

        //开始时间
        long startTime = System.currentTimeMillis();
        Object result = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 排除敏感字段
            PropertyPreFilters filters = new PropertyPreFilters();
            PropertyPreFilters.MySimplePropertyPreFilter excludeFilter = filters.addFilter();
            excludeFilter.addExcludes(SENSITIVE_FIELD_NAMES);
            log.info("返回结果：{}", JSONObject.toJSONString(result, excludeFilter));

            // 结束时间
            long endTime = System.currentTimeMillis();
            // 计算方法执行时间
            long executionTime = endTime - startTime;
            // 输出日志
            log.info("方法执行时间：{} ms", executionTime);
        } catch (Exception e) {
            log.error("执行方法异常：{}", e.getMessage());
        } finally {
            // 输出日志流水号
            log.info("日志流水号：{}", MDC.get("logId"));
            // 清除日志流水号
            MDC.clear();
        }
        return result;

    }

    // 获取客户端IP地址
    public static String getRemoteIPAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
